﻿interface JQuery {
    drawArc(opt: any): JQuery;
    drawLine(opt: any): JQuery;
    clearCanvas(): JQuery;
    translateCanvas(opt: any): JQuery;
    restoreCanvas(): JQuery;
    drawRect(opt: any): JQuery;
    drawText(opt: any): JQuery;
}

module SnakeModule {

    export class Game {
        canvas: JQuery;
        player: Snake;
        otherPlayers: Snake[]=[];
        //基本属性
        mapWidth = 4500;
        mapHeight = 3000;
        gridSize = 20;
        viewWidth = 900
        viewHeight = 600;
        //实时计算的地图偏移量
        tranPoint: Point = { x: 0, y: 0 };

        //分数的分散区域
        scoreZone: Score[][][] = null;
        szSize = 150;
        szCount = 6;
        constructor(name: string, canvas: JQuery) {
            var scope = this;
            this.player = new Snake(name);
            //for (var i = 0; i < 10; i++) {
            //    this.otherPlayers.push(new Snake("snake " + i));
            //}
            this.canvas = canvas;
            this.getMap(this.mapWidth, this.mapHeight, this.gridSize);
            //事件
            this.canvas.on("mousemove", function (event) {
                var x = event.offsetX, y = event.offsetY
                scope.playerRunto({ x, y });
            });
        }
        //运行起来
        public run() {
            this.ClearCanvas()
            this.GameMove();
            this.CalcTranPoint();//此时重新计算偏移量
            this.TranslateCanvas();
            this.DrawMap();
            this.DrawScores();
            this.DrawSnake(this.player);
            //this.otherPlayers.forEach((snake) => {
            //    this.DrawSnake(snake);
            //});
            this.RestoreCanvas();

            this.DrawInfo();
        }
        //玩家转向某点
        playerRunto(pt: Point) {
            //由于地图已经平移过了，所以要折算一下点击点在地图位置
            pt.x = pt.x - this.tranPoint.x;
            pt.y = pt.y - this.tranPoint.y;
            this.player.runToPoint(pt);
        }
        //玩家换色
        public playerChangeColor() {
            this.player.changeColor();
        }
        //游戏运行，玩家吃分
        GameMove() {
            this.player.move();
            //this.otherPlayers.forEach((snake) => {
            //    snake.move();
            //});
            if (!this.scoreZone) this.createMapScores();
            ////是否碰壁
            if (!isInRect(this.player.head, { x: this.player.r, y: this.player.r }, { x: this.mapWidth - this.player.r, y: this.mapHeight - this.player.r })) {
                this.player = new Snake(this.player.name); return;
            }
            //吃当前区域的分数
            var i = Math.floor(this.player.head.x / this.szSize), j = Math.floor(this.player.head.y / this.szSize);
            var zone = this.scoreZone[i][j];
            var flag = false;
            zone.forEach((s) => {
                if (distance(s.p, this.player.head) < (s.r + this.player.r)) {
                    s.isEated = true;
                    flag = true;
                    this.player.addLength(s.r);
                }
            })
            flag && (this.scoreZone[i][j] = zone.filter((s) => !s.isEated));
        }
        //点是否在可视区域
        IsInView(pt: Point): boolean {
            return isInRect(pt,
                { x: this.tranPoint.x * (-1), y: this.tranPoint.y * (-1) },
                { x: this.viewWidth - this.tranPoint.x, y: this.viewHeight - this.tranPoint.y });
        }
        //清除
        ClearCanvas() {
            this.canvas.clearCanvas();
        }
        //计算平移量
        CalcTranPoint() {
            this.tranPoint.x = Math.min(0, this.viewWidth / 2 - this.player.head.x);
            this.tranPoint.y = Math.min(0, this.viewHeight / 2 - this.player.head.y);
            this.tranPoint.x = Math.max(-1 * this.mapWidth + this.viewWidth, this.tranPoint.x);
            this.tranPoint.y = Math.max(-1 * this.mapHeight + this.viewHeight, this.tranPoint.y);
        }
        TranslateCanvas() {
            this.canvas.translateCanvas({
                translateX: this.tranPoint.x, translateY: this.tranPoint.y
            })
        }
        RestoreCanvas() {
            this.canvas.restoreCanvas();
        }
        //画蛇
        DrawSnake(snake:Snake) {
            /*两个触须*/
            this.canvas.drawLine({
                strokeStyle: '#000',
                strokeWidth: 4,
                rounded: true,
                startArrow: true,
                arrowRadius: 10,
                arrowAngle: 60,
                x1: snake.head.x,
                y1: snake.head.y,
                x2: snake.head.x + 0.1 * snake.r * Math.cos(snake.direction),
                y2: snake.head.y - 0.1 * snake.r * Math.sin(snake.direction),
            });
            this.canvas.drawArc({
                strokeStyle: '#000',
                strokeWidth: 1,
                x: snake.head.x,
                y: snake.head.y,
                radius: snake.r,
                fillStyle: snake.color,
            });
            snake.body.forEach((p) => {
                this.canvas.drawArc({
                    strokeStyle: '#000',
                    strokeWidth: 1,
                    x: p.x,
                    y: p.y,
                    radius: snake.r,
                    fillStyle: snake.color,

                });
            });

        }
        //创建地图
        private mapVLines: Object;
        private mapHLines: Object;
        getMap(width, height, size) {
            var obj = {
                strokeStyle: '#ccc',
                strokeWidth: 1,
                rounded: false
            };
            for (var i = 0; i < width / size; i++) {
                /*左上*/
                obj['x' + (i * 4 + 1)] = i * size;
                obj['y' + (i * 4 + 1)] = 0;
                /*左下*/
                obj['x' + (i * 4 + 2)] = i * size;
                obj['y' + (i * 4 + 2)] = height;
                /*右下*/
                obj['x' + (i * 4 + 3)] = (i + 1) * size;
                obj['y' + (i * 4 + 3)] = height;
                /*右上*/
                obj['x' + (i * 4 + 4)] = (i + 1) * size;
                obj['y' + (i * 4 + 4)] = 0;
            }
            this.mapVLines = obj
            obj = {
                strokeStyle: '#ccc',
                strokeWidth: 1,
                rounded: false
            };
            for (var i = 0; i < height / size; i++) {
                /*左上*/
                obj['x' + (i * 4 + 1)] = 0;
                obj['y' + (i * 4 + 1)] = i * size;
                /*右上*/
                obj['x' + (i * 4 + 2)] = width;
                obj['y' + (i * 4 + 2)] = i * size;
                /*右下*/
                obj['x' + (i * 4 + 3)] = width;
                obj['y' + (i * 4 + 3)] = (i + 1) * size;
                /*左下*/
                obj['x' + (i * 4 + 4)] = 0;
                obj['y' + (i * 4 + 4)] = (i + 1) * size;
            }
            this.mapHLines = obj
        }
        DrawMap() {
            this.canvas.drawLine(this.mapHLines);
            this.canvas.drawLine(this.mapVLines);
        }
        //创建右上角信息
        DrawInfo() {
            //右上定位
            var padding = 10, width = 180, heigth = 300;
            this.canvas.drawRect({
                fillStyle: 'rgba(0, 0, 153, 0.5)',
                x: this.viewWidth - width - padding, y: padding,
                width: width,
                height: heigth,
                fromCenter: false
            });
            var textStyle = {
                fillStyle: '#cfc',
                strokeWidth: 1,
                fontSize: '14px',
                fontFamily: 'Arial',
                fromCenter: false,
            }
            this.canvas.drawText($.extend({
                text: `${this.player.name}:${this.player.length}`, x: this.viewWidth - width,
                y: padding * 2
            }, textStyle));
            this.canvas.drawText($.extend({
                text: `head:(${Math.round(this.player.head.x)},${Math.round(this.player.head.y)})`, x: this.viewWidth - width,
                y: padding * 5
            }, textStyle));
        }
        //创建地图上的分数,分数是1~5分,20个点，对应相应半径的圆
        //划分区域，100*100，区域边界不产生分数点
        createMapScores() {
            //若没有分数区域时，则创建它
            if (!this.scoreZone) {
                this.scoreZone = [];
                for (var i = 0; i < this.mapWidth / this.szSize; i++) {
                    this.scoreZone.push([]);
                    for (var j = 0; j < this.mapHeight / this.szSize; j++) {
                        this.scoreZone[i].push([]);
                        for (var k = 0; k < this.szCount; k++) {
                            this.scoreZone[i][j].push(new Score(i * this.szSize + 5, j * this.szSize + 5, (i + 1) * this.szSize - 5, (j + 1) * this.szSize - 5));
                        }
                    }
                }
            } else {
                //更新每一个区域的分数
            }
        }
        //画出分数
        DrawScores() {

            for (var i = 0; i < this.scoreZone.length; i++) {
                for (var j = 0; j < this.scoreZone[i].length; j++) {
                    var scores = this.scoreZone[i][j];
                    scores.forEach((s) => {
                        if (this.IsInView(s.p)) {
                            this.canvas.drawArc({
                                strokeStyle: s.color,
                                strokeWidth: 1,
                                x: s.p.x,
                                y: s.p.y,
                                radius: s.r,
                                fillStyle: s.color,
                            });
                        }
                    });
                } //end j
            } //end i

        }//end drawscores
    }

    class Score {
        public p: Point;
        r: number = ran2(1, 5);
        color: string = ranColor();
        isEated: boolean = false;
        constructor(private x1: number, private y1: number, private x2: number, private y2: number) {
            this.p = { x: ran2(x1, x2), y: ran2(y1, y2) }
        }
    }
}